
function Promise(executor){
    //为实例对象添加属性值
    this.promiseState = 'pending'
    this.promiseResult = null
    //保存回调函数,如果是多组回调那就改用数组
    this.callback = []
    //采用闭包，保存函数上下文
    let self = this
    //try-catch
    try {
        //同步调用执行器函数
        executor(resolve,reject)
    } catch (error) {
        //直接通过调用函数修改
        reject(error)
    }
    function resolve(response){
        
        if (self.promiseState !== 'pending') return
       
        //通过判断当前状态去保证状态只能修改一次
        //注意self.promiseState == 'pending'，这样会报错，因为当异步任务(事件循环event loop)会进入死循环
        setTimeout(() => {
            self.callback.forEach(item => {
                //只是进行了结果对打印，没有真正地执行resolved函数，没有改变状态
                
                item.onResolved(response)
            })
        })
        
        
        self.promiseState = 'fulfilled'
       
        //promiseState = resolved
        self.promiseResult = response
       
      
    }
    function reject(response){
       
        if (self.promiseState !== 'pending') return
        //如果是多组的回调函数的话，对函数进行遍历
        //遍历对象
        setTimeout(() =>{
            self.callback.forEach(item => {
           
                item.onRejected(response)
            })
        })

        self.promiseState =  'rejected'
        self.promiseResult = response
        
        
    }
   
}
//为promise对象增加then方法
//Object.prototype是给所有的对象添加属性
//为什么不可以用箭头函数?
Promise.prototype.then = function(onResolved,onRejected){
    //我们需要的是promise对象本身,这样才方便修改后面对象的状态值
    //因为闭包原因，所以要进行保存
    let self = this
    //如果没有传参，给它默认值
    if (typeof onRejected  !== 'function'){
        onRejected = resonse =>{
            throw resonse
        }

    }
    if (typeof onResolved !== 'function'){
        onResolved = value => value
        
    }
    //返回Promise 对象是为了如果then方法返回的是Promise对象，可以再次
    //调用Promise 的resolved或者rejected
    return new Promise ((resolve,reject)=>{
        //f封装回调函数的结果

        function callback(type){
            try {
                    //onResolved(this.promiseResult)
                let result = type(self.promiseResult)
                //对返回结果进行判断
                if (result instanceof Promise){
                    result.then(v =>{
                        resolve(v)
                    },r =>{
                        reject(r)
                    })
                }else{
                    //通过调用resolve进行对结果状态进行修改
                    resolve(result)
                }
            } catch (e) {
                reject(e)
            }
            
        }
        if (this.promiseState == 'fulfilled'){
            //回调函数，异步执行，不是马上执行，所以可以用setTimeout进行延迟
            setTimeout(()=>{
                callback(onResolved)
            })
            
        }
        if (this.promiseState == 'rejected'){
            //还要判断是reject还是throw
            setTimeout(()=>{
                callback(onRejected)
            })
            
        }
        //针对setTimeout,promiseState没有改变，使得后面延时以后无法再次调用then方法
        //所以要保存回调函数then,那么怎么保存呢？保存在对象本身，(this)方便调用
        // 因为要利用promise对象对
        //状态进行修改，所以在promise函数的时候需要判断是否有保存函数，再调用then方法
        
        if(this.promiseState == 'pending'){
            this.callback.push({
                //这个的函数上下文指的是回调函数数组本身，我们需要的是
                //如果返回地是newPromise,因为没有调用返回对象地
                //resolved，reject的方法，所以没有改变状态
                onResolved:function (){
                    try {
                        //执行成功回调函数，修改状态
                        const res = onResolved(this.promiseResult)
                        //对结果类型进行判断
                        if (res instanceof Promise){
                            res.then(r=>{
                                self.resolve(r)
                            },v=>{
                                self.reject(v)
                            })
                        }else{
                            resolve(res)
                        }
                    } catch (e) {
                        reject(e)
                    }
                        

                },
                onRejected:function (){
                    try {
                        const res = onRejected(this.promiseResult)
                        //对结果类型进行判断
                        if (res instanceof Promise){
                            res.then(r=>{
                                self.resolve(r)
                            },v=>{
                                self.reject(v)
                            })
                        }else{
                            reject(res)
                        }
                    } catch (e) {
                        reject(e)
                    }
                        
                }
            })
        }
    })
    
   

}
//声明此方法，利用then解决抛出错误
Promise.prototype.catch = function(onRejected){
    return this.then(undefined,onRejected)
}
//resolve会根据括号里面的返回结果决定外面的返回值
Promise.resolve = function(v){
    return new Promise ((resolve,rejected) => {
        if(v instanceof Promise){
            v.then(v =>{
                resolve(v)
            },e =>{
                rejected(e)
            })
        }else{
            resolve(v)
        }

    })
}
//reject无论里面是成功还是失败，结果都是失败的
Promise.reject = function(v){
    return new Promise ((resolve,reject) => {
        reject(v)
    })
}
Promise.all = function(arr){
  return new Promise((res,rej) =>{
      //声明数组
        let resarr = []
        let count = 0
      //对传入的数组进行遍历
        for (let i = 0 ;i < arr.length;i++){
            //对于每个promise进行遍历确定都是成功才能resolve
            arr[i].then(r =>{
                    //用count记录是否数组里面全部都是成功的
                    count ++
                    //现将数组里面的存储，但是如果直接用push可能会乱序
                    //利用下标对成功对回调函数进行存储
                    resarr[i] = r
                    if (count === arr.length){
                        res(resarr)
                    }
            },e =>{
                //如果数组里面有个是失败的，直接走这个reject，
                //返回这个失败的回调函数
                rej(e)
            })
        }
  })

}
Promise.race = function(promise){
    return new Promise((reject,resolve) =>{
        for (let i = 0 ;i <promise.length;i++){
            promise[i].then(r =>{
                resolve(r)
            },v => {
                reject(v)
            })
        }
    })
}
